﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ServerSide.Communication;
using CustomProvider;
using CustomProvider.Event;
using System.Net;
using System.Threading;
using System.ComponentModel;
using System.Threading.Tasks;
using ServerSide.Model;
using System.Collections.ObjectModel;

namespace ServerSide
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Fields

        /// <summary>
        /// The server build with Asynchronous Socket for communication with Clients
        /// </summary>
        private AsynSocket asynSocket = new AsynSocket();

        /// <summary>
        /// Player collection for binding to listview
        /// </summary>
        public ObservableCollection<Player> Players { get; set; }

        #endregion

        #region Constructor

        public MainWindow()
        {
            InitializeComponent();
            this.SubscribeNotifyDisplayMessageOnGUIEvent();
            this.SubscribeNotifyConnectStatusEvent();
            this.SubscribeNotifyEndGamevent();

            txtServerAddress.Text = "127.0.0.1";// SocketProvider.RetrieveIPAddress();

            // Load WordList
            WordList.GetInstance();
            this.Players = new ObservableCollection<Player>();
            this.DataContext = this;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Notify the connection status
        /// </summary>
        private void SubscribeNotifyEndGamevent()
        {
            EventAggregatorFactory.Instance.GetEvent<NotifyEndGameEvent>().Subscribe((EventData) =>
            {
                Action action = () =>
                {
                    var idWinner = EventData;
                    var player = this.Players.FirstOrDefault(n => n.IDPlayer.Equals(idWinner));
                    if (player != null)
                    {
                        // Update points
                        player.Score++;
                        txtServerStatus.AppendText(string.Format("{0} The player {1} is the winner", 
                            DateTime.Now.ToString(), idWinner) + Environment.NewLine);
                    }
                };
                this.Dispatcher.Invoke(action);
            }, false);
        }

        /// <summary>
        /// Notify the connection status
        /// </summary>
        private void SubscribeNotifyConnectStatusEvent()
        {
            EventAggregatorFactory.Instance.GetEvent<NotifyConnectStatusEvent>().Subscribe((EventData) =>
            {
                Action action = () =>
                {
                    if (EventData.IsConnected)
                        this.Players.Add(new Player(EventData.PlayerInfo.Name, EventData.PlayerInfo.IPAddress));
                    else
                    {
                        var idPlayerToRemove = EventData.PlayerInfo.Name + "@" + EventData.PlayerInfo.IPAddress;
                        var playerToRemove = this.Players.FirstOrDefault(n => n.IDPlayer.Equals(idPlayerToRemove));
                        if (playerToRemove != null)
                        {
                            this.Players.Remove(playerToRemove);
                            if (this.Players.Count > 0)
                                this.Players[0].Score = 0;
                        }
                    }
                };
                this.Dispatcher.Invoke(action);
            }, false);
        }

        /// <summary>
        /// Display message on user interface
        /// </summary>
        private void SubscribeNotifyDisplayMessageOnGUIEvent()
        {
            EventAggregatorFactory.Instance.GetEvent<NotifyDisplayMessageOnGUIEvent>().Subscribe((EventData) =>
            {
                Action action = () =>
                {
                    txtServerStatus.AppendText(EventData + Environment.NewLine);
                };
                this.Dispatcher.Invoke(action);
            }, false);
        }

        /// <summary>
        /// Validate input by user such as port and server address
        /// </summary>
        /// <returns>true: valid and false: invalid</returns>
        private bool ValidateInputs(ref string errTxt)
        {
            if (txtServerAddress.Text.Equals(string.Empty))
            {
                errTxt = "Server address is empty";
                return false;
            }
            if (txtServerPort.Text.Equals(string.Empty))
            {
                errTxt = "Server port is empty";
                return false;
            }
            if (txtServerPort.Text.IsNumeric() == false)
            {
                errTxt = "Server port must be numeric";
                return false;
            }
            return true;
        }

        /// <summary>
        /// Start listening connections from Clients
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            var errTxt = string.Empty;
            if (ValidateInputs(ref errTxt) == false)
            {
                MessageBox.Show(errTxt, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            // Get server information
            var serverAddress = txtServerAddress.Text;
            var serverPort = int.Parse(txtServerPort.Text.Trim());

            // Disable Start Listening
            this.btnStart.IsEnabled = false;
            this.btnStop.IsEnabled = true;

            Action action = () =>
            {
                this.asynSocket.StartListening(serverAddress, serverPort);
            };
            Task task = new Task(action);
            task.Start();
        }

        /// <summary>
        /// Stop connections with CLients
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            this.asynSocket.CloseSockets();
            // Enable Start Listening
            this.btnStart.IsEnabled = true;
            this.btnStop.IsEnabled = false;
        }

        private void btnClear_Click(object sender, RoutedEventArgs e)
        {
            txtServerStatus.Clear();
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            this.asynSocket.CloseSockets();
        }

        #endregion
    }
}
